#include "stdafx.h"
#include "Globals.h"
#include "AdcDump.h"


CAdcDump::CAdcDump(void)
	: m_nPollingPeriod(0), 
	  m_pDataReceiver(NULL), 
	  m_hFile(NULL), m_hMap(NULL), m_nRequests(0LL)
{
	m_TimerClient.SetExecutive(this, &CAdcDump::OnTimer);
	m_iFileSize.QuadPart = 0LL;
	::QueryPerformanceFrequency(&m_iFreq);
}

CAdcDump::~CAdcDump(void)
{
	if (m_hFile)
	{
		Close();
		m_hFile = NULL;
		m_iFileSize.QuadPart = 0LL;
	}
	m_TimerClient.ResetExecutive();
}



BOOL CAdcDump::Open(const void * pInitData)
{
	const TCHAR * pszDumpFileName = static_cast <const TCHAR *> (pInitData);

	m_hFile = ::CreateFile(
			pszDumpFileName, 
			GENERIC_READ, 
			FILE_SHARE_READ, 
			NULL, 
			OPEN_EXISTING, 
			FILE_FLAG_RANDOM_ACCESS, 
			NULL
		);

	if ( m_hFile == INVALID_HANDLE_VALUE )
	{
		m_hFile = NULL;
		return FALSE;
	}

	::GetFileSizeEx(m_hFile, &m_iFileSize);

	m_hMap = ::CreateFileMapping(m_hFile, NULL, PAGE_READONLY, m_iFileSize.HighPart, m_iFileSize.LowPart, NULL);

	if ( !m_hMap )
	{
		::CloseHandle(m_hFile);
		m_hFile = NULL;

		return FALSE;
	}

	m_pDumpData = (SHORT *) ::MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0);

	if ( !m_pDumpData )
	{
		::CloseHandle(m_hMap);
		m_hMap = NULL;
		::CloseHandle(m_hFile);
		m_hFile = NULL;

		return FALSE;
	}

	if ( FAILED( m_WorkerThread.Initialize() ) )
	{
		::UnmapViewOfFile(m_pDumpData);
		m_pDumpData = NULL;
		::CloseHandle(m_hMap);
		m_hMap = NULL;
		::CloseHandle(m_hFile);
		m_hFile = NULL;

		return FALSE;
	}

	const SIZE_T nBufferSize = ADC_PAGES * ADC_IRQSTEP_SAMPLES;

	m_fKadrRate = ADC_FREQ / ADC_FRAME_PERIOD;
	m_nPollingPeriod = (ULONG)(
		(nBufferSize / (m_fKadrRate * ADC_FRAME_LENGTH * sizeof(SHORT))) / (2 * BLOCKS)
		);

	return TRUE;
}

BOOL CAdcDump::Start(IDataReceiver * pDataReceiver)
{
	if (!m_hMap || !m_pDumpData || !pDataReceiver)
		return FALSE;

	m_pDataReceiver = pDataReceiver;

	::QueryPerformanceCounter(&m_iTime);

	m_nRequests = 0LL;

	if ( FAILED( m_TimerClient.Connect(&m_WorkerThread, m_nPollingPeriod) ) )
	{
		m_pDataReceiver = NULL;
		return FALSE;
	}

	return TRUE;
}

HRESULT CAdcDump::OnTimer(DWORD_PTR /*dwParam*/)
{
	static const ULONG64 nBlockLen = 
		(ADC_IRQSTEP_SAMPLES * ADC_PAGES) / (BLOCKS * sizeof(SHORT));
	static const LONG64 nBlockTimeout = 
		(nBlockLen * m_iFreq.QuadPart) / (ADC_FRAME_LENGTH * m_fKadrRate * 1000.0);

	LARGE_INTEGER iTime;
	::QueryPerformanceCounter(&iTime);

	ASSERT(m_pDataReceiver);

	if ( iTime.QuadPart - m_iTime.QuadPart >= nBlockTimeout * (m_nRequests + 1) )
	{
		const ULONG64 nMaxReq = m_iFileSize.QuadPart / (sizeof(SHORT) * nBlockLen);
		m_pDataReceiver->ReadData(m_pDumpData + nBlockLen * (m_nRequests % nMaxReq), nBlockLen);
		m_nRequests++;
	}
	return S_OK;
}


void CAdcDump::Stop(void)
{
	m_TimerClient.Disconnect();
	m_pDataReceiver = NULL;
}

void CAdcDump::Close(void)
{
	m_WorkerThread.Shutdown();

	if (m_pDumpData)
	{
		::UnmapViewOfFile(m_pDumpData);
		m_pDumpData = NULL;
	}
	if (m_hMap)
	{
		::CloseHandle(m_hMap);
		m_hMap = NULL;
	}
	if (m_hFile)
	{
		::CloseHandle(m_hFile);
		m_hFile = NULL;
	}
}

